package com.dayu.finecomm.device;

import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

import com.dayu.finecomm.decoder.HdUdpDecoder;
import com.dayu.finecomm.handler.DistributeHandler;
import com.dayu.finecomm.handler.cmd.CMDSendHandler;
import com.dayu.finecomm.handler.tpacket.TPacketCollectHandler;
import com.dayu.finecomm.handler.tpacket.TPacketCommitHandler;
import com.dayu.finecomm.handler.tpacket.TPacketOPCUAHandler;
import com.dayu.finecomm.handler.tpacket.TPacketPushHandler;
import com.dayu.finecomm.pojo.DeviceConfig;
import com.dayu.finecomm.pojo.DevicePusher;
import com.dayu.finecomm.protocol.ProtocolPacket;
import com.dayu.finecomm.protocol.Protocols;
import com.dayu.finecomm.protocol.codec.Drive;
import com.dayu.finecomm.protocol.log.ProtocolLogger;
import com.dayu.finecomm.protocol.log.UnProtocolLogger;
import com.dayu.finecomm.source.CollectSource;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.nio.NioDatagramChannel;

/**
 * UDP设备
 * 
 * @author Lijiajie
 * 
 */
@Drive(UdpDevice.DRIVE)
public class UdpDevice extends ChannelInitializer<NioDatagramChannel> implements Device {

	static final String DRIVE = "udp";

	static class PacketPacker extends ChannelInboundHandlerAdapter {

		@Override
		public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

			if (!(msg instanceof ByteBuf)) {
				ctx.fireChannelRead(msg);
				return;
			}

			ctx.fireChannelRead(new ProtocolPacket(((ByteBuf) msg).slice(), false));
		}
	}

	private Map<String, ChannelHandlerContext> listeners;

	final Set<String> protocols;
	private Set<InetSocketAddress> distributors;

	final DeviceConfig config;

	final String prefix;

	private String listenType;

	private Collection<DevicePusher> pushers;

	private CollectSource stations;

	@Override
	public Collection<DevicePusher> getPushers() {
		return pushers;
	}

	@Override
	public void setPushers(Collection<DevicePusher> pushers) {
		this.pushers = pushers;
	}

	public UdpDevice(final CollectSource stations, final Set<String> protocols, final DeviceConfig config) {

		this.stations = stations;
		this.protocols = protocols;
		this.prefix = config.prefix;
		this.config = config;
	}

	@Override
	protected void initChannel(NioDatagramChannel ctx) throws Exception {

		ChannelPipeline pipeline = ctx.pipeline();

		pipeline.addLast(new DistributeHandler(this));

		pipeline.addLast(new HdUdpDecoder(this.prefix, Protocols.protocols(this.protocols)));

		pipeline.addLast(new TPacketCommitHandler(this));
		// pipeline.addLast(new CMDStoreHandler(stations));

		pipeline.addLast(new TPacketCollectHandler(stations, true, config.name));
		pipeline.addLast(new TPacketPushHandler(this, config));

		if (config.opcUaEnabled) {
			pipeline.addLast(new TPacketOPCUAHandler(config.opcUaEndPoint));
		}

		pipeline.addLast(new CMDSendHandler(stations));

		pipeline.addLast(new PacketPacker());
		pipeline.addLast(new ProtocolLogger());
		pipeline.addLast(new UnProtocolLogger());
	}

	@Override
	public Map<String, ChannelHandlerContext> getListeners() {
		return listeners;
	}

	@Override
	public void setListeners(Map<String, ChannelHandlerContext> LITENERS) {
		listeners = LITENERS;
	}

	@Override
	public Set<InetSocketAddress> getDistributors() {
		return distributors;
	}

	@Override
	public void setDistributors(Set<InetSocketAddress> distributors) {
		this.distributors = distributors;
	}

	@Override
	public String getListenType() {
		return listenType;
	}

	@Override
	public void setListenType(String listenType) {
		this.listenType = listenType;
	}

}